package top.jiangqiang.qianyi.common.storage.impl;

import jakarta.annotation.PreDestroy;
import jakarta.servlet.http.HttpServletRequest;
import lombok.SneakyThrows;
import lombok.extern.slf4j.Slf4j;
import org.dromara.hutool.core.io.IoUtil;
import org.dromara.hutool.core.io.NioUtil;
import org.dromara.hutool.core.io.StreamProgress;
import org.dromara.hutool.core.io.file.FileNameUtil;
import org.dromara.hutool.core.io.file.FileUtil;
import org.dromara.hutool.core.text.StrUtil;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.util.UriUtils;
import top.jiangqiang.qianyi.common.constants.GlobalConstants;
import top.jiangqiang.qianyi.common.constants.http.Error404Status;
import top.jiangqiang.qianyi.common.exception.Error404Exception;
import top.jiangqiang.qianyi.common.id.IDGenerator;
import top.jiangqiang.qianyi.common.storage.AbstractStorageService;
import top.jiangqiang.qianyi.common.storage.ProgressContext;
import top.jiangqiang.qianyi.common.storage.config.LocalStorageConfig;

import java.io.File;
import java.io.InputStream;
import java.io.OutputStream;
import java.nio.charset.StandardCharsets;
import java.util.function.Consumer;

/**
 * @Date 2024/7/5 下午5:13
 * @Author Jiangqiang
 */
@Slf4j
public class LocalStorageService extends AbstractStorageService<LocalStorageConfig> {
    public LocalStorageService(IDGenerator idGenerator, LocalStorageConfig localStorageConfig, String cachePath) {
        super(idGenerator, localStorageConfig, cachePath);
    }

    @Override
    public boolean test() {
        return true;
    }

    @Override
    public String generateFileKey(String originalFilename) {
        String fileKey;
        do {
            fileKey = idGenerator.nextUUID() + "." + FileNameUtil.extName(originalFilename);
        } while (fileKeyToFile(fileKey).exists());
        return fileKey;
    }

    @Override
    @SneakyThrows
    public String upload(String originalFilename, InputStream inputStream, Consumer<ProgressContext> progressCallback) {
        String fileKey = generateFileKey(originalFilename);
        long size = inputStream.available();
        IoUtil.copy(inputStream, FileUtil.getOutputStream(fileKeyToFile(fileKey)), NioUtil.DEFAULT_BUFFER_SIZE, size, new StreamProgress() {
            @Override
            public void start() {
                if (progressCallback != null) {
                    ProgressContext progressContext = new ProgressContext();
                    progressContext.setProgress(0D);
                    progressContext.setComplete(false);
                    progressContext.setFileKey(fileKey);
                    progressCallback.accept(progressContext);
                }

            }

            @Override
            public void progress(long total, long progressSize) {
                if (progressCallback != null) {
                    ProgressContext progressContext = new ProgressContext();
                    progressContext.setProgress((double) progressSize / total);
                    progressContext.setComplete(false);
                    progressContext.setFileKey(fileKey);
                    progressCallback.accept(progressContext);
                }
            }

            @Override
            public void finish() {
                if (progressCallback != null) {
                    ProgressContext progressContext = new ProgressContext();
                    progressContext.setProgress(1D);
                    progressContext.setComplete(true);
                    progressContext.setFileKey(fileKey);
                    progressCallback.accept(progressContext);
                }
            }
        });
        return fileKey;
    }

    @Override
    public void download(String fileKey, OutputStream outputStream) {
        File file = fileKeyToFile(fileKey);
        if (!file.exists()) {
            throw new Error404Exception(Error404Status.NOT_FOUND);
        } else {
            FileUtil.copy(file, outputStream);
        }
    }

    @Override
    public byte[] download(String fileKey) {
        File file = fileKeyToFile(fileKey);
        if (!file.exists()) {
            throw new Error404Exception(Error404Status.NOT_FOUND);
        } else {
            return FileUtil.readBytes(file);
        }
    }

    /**
     * 根据fileKey拼接文件完整路径
     *
     * @param fileKey 文件唯一key，本地文件存储中实际上就是相对路径
     * @return
     */
    private File fileKeyToFile(String fileKey) {
        String uploadPath = getStorageConfig().getUploadPath();
        return FileUtil.file(uploadPath, fileKey);
    }

    /**
     * 如果未配置访问协议，则与当前请求保持一致
     * 如果未配值域名，则使用当前请求访问的ip和端口号代替，此时会额外拼接一个访问文件的公共前缀，该前缀是文件访问接口的前面部分，因此为了保证统一，建议使用域名访问
     * 否则直接使用配置中的域名和协议拼接
     *
     * @param fileKey
     * @return
     */
    @Override
    public String getUrl(String fileKey) {
//        String objectURL;
//        String accessProtocol;
//        HttpServletRequest request = ((ServletRequestConfig) (RequestContextHolder.currentRequestConfig())).getRequest();
//        if (storageConfig.getAccessProtocol() != null) {
//            accessProtocol = storageConfig.getAccessProtocol().getProtocolName();
//        } else {
//            //获取当前请求时使用的协议
//            accessProtocol = request.getScheme();
//        }
//        if (StrUtil.isNotBlank(storageConfig.getDomain())) {
//            objectURL = accessProtocol + "://" + storageConfig.getDomain() + "/" + fileKey;
//        } else {
//            objectURL = accessProtocol + "://" + request.getHeader("Host") + request.getContextPath() + GlobalConstants.CommonRequestURLConstants.COMMON_FILE_ACCESS_API_FULL_PREFIX + "/" + fileKey;
//        }
//        return UriUtils.encodePath(objectURL, StandardCharsets.UTF_8);
        return null;
    }

    @Override
    public boolean delete(String fileKey) {
        File file = fileKeyToFile(fileKey);
        if (!file.exists()) {
            throw new Error404Exception(Error404Status.NOT_FOUND);
        } else {
            FileUtil.del(file);
        }
        return true;
    }

    @PreDestroy
    @Override
    public void cleanup() {
        //本地存储暂时不需要清理资源
    }
}
